package com.bj58.mis.apm.server.kylin.common.util;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

public class BytesUtil {
    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];

    public BytesUtil() {
    }

    public static void writeByte(byte num, byte[] bytes, int offset, int size) {
        for(int i = offset + size - 1; i >= offset; --i) {
            bytes[i] = num;
            num = (byte)(num >>> 8);
        }

    }

    public static void writeShort(short num, byte[] bytes, int offset, int size) {
        for(int i = offset + size - 1; i >= offset; --i) {
            bytes[i] = (byte)num;
            num = (short)(num >>> 8);
        }

    }

    public static byte[] writeShort(short num) {
        byte[] output = new byte[2];
        writeShort(num, output, 0, output.length);
        return output;
    }

    public static long readShort(byte[] bytes, int offset, int size) {
        short num = 0;
        int i = offset;

        for(int n = offset + size; i < n; ++i) {
            num = (short)(num << 8);
            num = (short)(num | (short)bytes[i] & 255);
        }

        return (long)num;
    }

    public static short readShort(byte[] bytes) {
        return (short)((int)readShort(bytes, 0, 2));
    }

    public static void writeUnsigned(int num, byte[] bytes, int offset, int size) {
        for(int i = offset + size - 1; i >= offset; --i) {
            bytes[i] = (byte)num;
            num >>>= 8;
        }

    }

    public static int readUnsigned(byte[] bytes, int offset, int size) {
        int integer = 0;
        int i = offset;

        for(int n = offset + size; i < n; ++i) {
            integer <<= 8;
            integer |= bytes[i] & 255;
        }

        return integer;
    }

    public static void writeUnsigned(int num, int size, ByteBuffer out) {
        int mask = 255 << (size - 1) * 8;

        for(int i = size; i > 0; --i) {
            int v = (num & mask) >> (i - 1) * 8;
            out.put((byte)v);
            mask >>= 8;
        }

    }

    public static int readUnsigned(ByteBuffer in, int size) {
        int integer = 0;

        for(int i = 0; i < size; ++i) {
            integer <<= 8;
            integer |= in.get() & 255;
        }

        return integer;
    }

    public static int readUnsigned(ByteArray in, int offset, int size) {
        int integer = 0;
        offset += in.offset();
        byte[] bytes = in.array();
        int i = offset;

        for(int n = offset + size; i < n; ++i) {
            integer <<= 8;
            integer |= bytes[i] & 255;
        }

        return integer;
    }

    public static void writeSignedLong(long num, byte[] bytes, int offset, int size) {
        writeLong(num, bytes, offset, size);
    }

    public static long readSignedLong(byte[] bytes, int offset, int size) {
        long integer = (bytes[offset] & 128) == 0 ? 0L : -1L;
        int i = offset;

        for(int n = offset + size; i < n; ++i) {
            integer <<= 8;
            integer |= (long)(bytes[i] & 255);
        }

        return integer;
    }

    public static void writeLong(long num, byte[] bytes, int offset, int size) {
        for(int i = offset + size - 1; i >= offset; --i) {
            bytes[i] = (byte)((int)num);
            num >>>= 8;
        }

    }

    public static long readLong(byte[] bytes, int offset, int size) {
        long integer = 0L;
        int i = offset;

        for(int n = offset + size; i < n; ++i) {
            integer <<= 8;
            integer |= (long)bytes[i] & 255L;
        }

        return integer;
    }

    public static void writeLong(long num, ByteBuffer out) {
        for(int i = 0; i < 8; ++i) {
            out.put((byte)((int)num));
            num >>>= 8;
        }

    }

    public static long readLong(ByteBuffer in) {
        long integer = 0L;
        long mask = 255L;
        int shift = 0;

        for(int i = 0; i < 8; ++i) {
            integer |= (long)(in.get() << shift) & mask;
            mask <<= 8;
            shift += 8;
        }

        return integer;
    }

    public static int sizeForValue(long maxValue) {
        int size;
        for(size = 0; maxValue > 0L; maxValue >>>= 8) {
            ++size;
        }

        return size;
    }

    public static int compareByteUnsigned(byte b1, byte b2) {
        int i1 = b1 & 255;
        int i2 = b2 & 255;
        return i1 - i2;
    }

    public static byte[] subarray(byte[] bytes, int start, int end) {
        byte[] r = new byte[end - start];
        System.arraycopy(bytes, start, r, 0, r.length);
        return r;
    }

    public static int compareBytes(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) {
        int r = 0;

        for(int i = 0; i < length; ++i) {
            r = src[srcOffset + i] - dst[dstOffset + i];
            if (r != 0) {
                break;
            }
        }

        return r;
    }

    public static boolean isPositiveShort(int i) {
        return (i & -32768) == 0;
    }

    public static void writeVInt(int i, ByteBuffer out) {
        writeVLong((long)i, out);
    }

    public static void writeVLong(long i, ByteBuffer out) {
        if (i >= -112L && i <= 127L) {
            out.put((byte)((int)i));
        } else {
            int len = -112;
            if (i < 0L) {
                i = ~i;
                len = -120;
            }

            for(long tmp = i; tmp != 0L; --len) {
                tmp >>= 8;
            }

            out.put((byte)len);
            len = len < -120 ? -(len + 120) : -(len + 112);

            for(int idx = len; idx != 0; --idx) {
                int shiftbits = (idx - 1) * 8;
                long mask = 255L << shiftbits;
                out.put((byte)((int)((i & mask) >> shiftbits)));
            }

        }
    }

    public static long readVLong(ByteBuffer in) {
        byte firstByte = in.get();
        int len = decodeVIntSize(firstByte);
        if (len == 1) {
            return (long)firstByte;
        } else {
            long i = 0L;

            for(int idx = 0; idx < len - 1; ++idx) {
                byte b = in.get();
                i <<= 8;
                i |= (long)(b & 255);
            }

            return isNegativeVInt(firstByte) ? ~i : i;
        }
    }

    public static int readVInt(ByteBuffer in) {
        long n = readVLong(in);
        if (n <= 2147483647L && n >= -2147483648L) {
            return (int)n;
        } else {
            throw new IllegalArgumentException("value too long to fit in integer");
        }
    }

    private static boolean isNegativeVInt(byte value) {
        return value < -120 || value >= -112 && value < 0;
    }

    private static int decodeVIntSize(byte value) {
        if (value >= -112) {
            return 1;
        } else {
            return value < -120 ? -119 - value : -111 - value;
        }
    }

    public static void writeUTFString(String str, ByteBuffer out) {
        byte[] bytes = str == null ? null : Bytes.toBytes(str);
        writeByteArray(bytes, out);
    }

    public static String readUTFString(ByteBuffer in) {
        byte[] bytes = readByteArray(in);
        return bytes == null ? null : Bytes.toString(bytes);
    }

    public static void writeAsciiString(String str, ByteBuffer out) {
        if (str == null) {
            writeVInt(-1, out);
        } else {
            int len = str.length();
            writeVInt(len, out);

            for(int i = 0; i < len; ++i) {
                out.put((byte)str.charAt(i));
            }

        }
    }

    public static String readAsciiString(ByteBuffer in) {
        int len = readVInt(in);
        if (len < 0) {
            return null;
        } else {
            try {
                String result;
                if (in.hasArray()) {
                    int pos = in.position();
                    result = new String(in.array(), pos, len, "ISO-8859-1");
                    in.position(pos + len);
                } else {
                    byte[] tmp = new byte[len];
                    in.get(tmp);
                    result = new String(tmp, "ISO-8859-1");
                }

                return result;
            } catch (UnsupportedEncodingException var4) {
                throw new RuntimeException(var4);
            }
        }
    }

    public static void writeAsciiStringArray(String[] strs, ByteBuffer out) {
        writeVInt(strs.length, out);

        for(int i = 0; i < strs.length; ++i) {
            writeAsciiString(strs[i], out);
        }

    }

    public static String[] readAsciiStringArray(ByteBuffer in) {
        int len = readVInt(in);
        String[] strs = new String[len];

        for(int i = 0; i < len; ++i) {
            strs[i] = readAsciiString(in);
        }

        return strs;
    }

    public static void writeIntArray(int[] array, ByteBuffer out) {
        if (array == null) {
            writeVInt(-1, out);
        } else {
            writeVInt(array.length, out);

            for(int i = 0; i < array.length; ++i) {
                writeVInt(array[i], out);
            }

        }
    }

    public static int[] readIntArray(ByteBuffer in) {
        int len = readVInt(in);
        if (len < 0) {
            return null;
        } else {
            int[] array = new int[len];

            for(int i = 0; i < len; ++i) {
                array[i] = readVInt(in);
            }

            return array;
        }
    }

    public static void writeByteArray(byte[] array, ByteBuffer out) {
        if (array == null) {
            writeVInt(-1, out);
        } else {
            writeVInt(array.length, out);
            out.put(array);
        }
    }

    public static void writeByteArray(byte[] array, int offset, int length, ByteBuffer out) {
        if (array == null) {
            writeVInt(-1, out);
        } else {
            writeVInt(length, out);
            out.put(array, offset, length);
        }
    }

    public static byte[] readByteArray(ByteBuffer in) {
        int len = readVInt(in);
        if (len < 0) {
            return null;
        } else {
            byte[] array = new byte[len];
            in.get(array);
            return array;
        }
    }

    public static int peekByteArrayLength(ByteBuffer in) {
        int start = in.position();
        int arrayLen = readVInt(in);
        int sizeLen = in.position() - start;
        in.position(start);
        return arrayLen < 0 ? sizeLen : sizeLen + arrayLen;
    }

    public static void writeBooleanArray(boolean[] array, ByteBuffer out) {
        if (array == null) {
            writeVInt(-1, out);
        } else {
            writeVInt(array.length, out);
            byte b_true = 1;
            byte b_false = 0;

            for(int i = 0; i < array.length; ++i) {
                if (array[i]) {
                    out.put(b_true);
                } else {
                    out.put(b_false);
                }
            }

        }
    }

    public static boolean[] readBooleanArray(ByteBuffer in) {
        int len = readVInt(in);
        if (len < 0) {
            return null;
        } else {
            boolean[] array = new boolean[len];
            byte b_true = 1;

            for(int i = 0; i < array.length; ++i) {
                byte temp = in.get();
                if (temp == b_true) {
                    array[i] = true;
                } else {
                    array[i] = false;
                }
            }

            return array;
        }
    }

    public static String toReadableText(byte[] array) {
        return array == null ? null : toHex(array);
    }

    public static byte[] fromReadableText(String text) {
        String[] tokens = text.split("\\\\x");
        byte[] ret = new byte[tokens.length - 1];

        for(int i = 1; i < tokens.length; ++i) {
            int x = Bytes.toBinaryFromHex((byte)tokens[i].charAt(0));
            x = x << 4;
            int y = Bytes.toBinaryFromHex((byte)tokens[i].charAt(1));
            ret[i - 1] = (byte)(x + y);
        }

        return ret;
    }

    public static String toHex(byte[] array) {
        return toHex(array, 0, array.length);
    }

    public static String toHex(byte[] array, int offset, int length) {
        StringBuilder sb = new StringBuilder(length * 4);

        for(int i = 0; i < length; ++i) {
            int b = array[offset + i];
            sb.append(String.format("\\x%02X", b & 255));
        }

        return sb.toString();
    }
}
